package com.ymx.darling.cursor;

import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.build.Configuration;
import com.ymx.darling.exception.CursorException;
import com.ymx.darling.exception.ExceptionWrapper;
import com.ymx.darling.executor.mapping.handler.ResultSetHandler;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;

/**
 * @author 爱Java的小于
 * @param <T>
 */
public class DefaultCursor<T> implements Cursor<T>{
    private final PreparedStatement preparedStatement;
    private final ResultSetHandler<T> resultSetHandler;
    private final int fetchSize;
    private ResultSet resultSet;
    private boolean isConsumed;
    private int currentIndex;
    private boolean isOpen;
    private Ite iterator;

    public DefaultCursor(PreparedStatement preparedStatement, Statement statement) {
        Configuration configuration = statement.getConfiguration();
        this.resultSetHandler = (ResultSetHandler<T>) configuration.createResultSetHandler(statement);
        this.preparedStatement = preparedStatement;
        this.fetchSize = statement.getFaceSize();
        this.isOpen = true; //游标默认打开
        this.isConsumed = false;
        this.currentIndex = 0;
    }

    private Ite getIterator() {
        if (this.iterator == null) {
            try {
                preparedStatement.setFetchSize(this.fetchSize);
                this.resultSet = preparedStatement.executeQuery();
                this.iterator = new Ite(resultSet);
            } catch (SQLException e) {
                throw new ExceptionWrapper(e, e.getMessage());
            }
        }
        return this.iterator;
    }

    @Override
    public boolean isOpen() {
        return this.isOpen;
    }

    @Override
    public boolean isConsumed() {
        return this.isConsumed;
    }

    @Override
    public int getCurrentIndex() {
        return this.currentIndex;
    }

    @Override
    public void close() {
        if (resultSet != null)
            this.close(resultSet);
        if (preparedStatement != null)
            this.close(preparedStatement);
    }

    private void close(AutoCloseable autoCloseable) {
        try {
            this.isOpen = false;
            autoCloseable.close();
        } catch (Exception e) {
            throw new CursorException(e, "关闭Cursor时发生错误:"+e.getMessage());
        }
    }

    @Override
    public Iterator<T> iterator() {
        return this.getIterator();
    }


    private class Ite implements Iterator<T> {
        private ResultSet resultSet;
        private final ResultSetHandler<T> resultSetHandler = DefaultCursor.this.resultSetHandler;

        public Ite(ResultSet resultSet) {
            ini(resultSet);
        }

        private void ini(ResultSet resultSet){
            this.resultSet = resultSet;
        }

        @Override
        public boolean hasNext() {
            try {
                boolean next = resultSet.next();
                DefaultCursor.this.isConsumed = !next;
                return next;
            } catch (SQLException e) {
                throw new CursorException(e, e.getMessage());
            }
        }

        @Override
        public T next() {
            try {
                ++DefaultCursor.this.currentIndex;
                return this.resultSetHandler.handleCursor(resultSet);
            } catch (SQLException e) {
                throw new CursorException(e, e.getMessage());
            }
        }
    }
}
